﻿using CommonDevelop;
using CommonDevelop.Scene;
using CommonEngine;
using CommonEngine.Power;
using CommonFP;
using ManageDB;
using System.Collections.Generic;
using System.Linq;

namespace ManageService
{
    /// <summary>
    /// 面向接口开发，配合Ioc
    /// </summary>
    public interface IPermissionManager
    {
        /// <summary>
        /// 获取菜单树
        /// </summary>
        List<TreeBox> GetModuleTree();

        #region--角色配置--

        /// <summary>
        /// 获取角色的菜单配置
        /// </summary>
        Dictionary<string, bool> GetRoleModuleID(string RoleId);
        /// <summary>
        /// 保存角色的菜单配置项
        /// </summary>
        bool SaveModuleTree(string RoleId, List<SimpleItem> data);

        #endregion

        #region--用户配置--

        /// <summary>
        /// 获取用户的角色勾选清单
        /// </summary>
        List<RoleModel> GetRoleListCheck(string userId);
        /// <summary>
        /// 获取用户的角色
        /// </summary>
        List<RoleModel> GetRoleList(string userId);

        /// <summary>
        /// 保存用户的角色配置项
        /// </summary>
        bool SaveURConfig(string userId, List<RoleModel> Rolels);

        #endregion

        #region--获取权限配置--

        /// <summary>
        /// 获取角色配置的模块（菜单）资源
        /// </summary>
        List<ModuleModel> GetModuleFromRole(string roleId);
        /// <summary>
        /// 用户获取菜单
        /// </summary>
        List<SysMenu> GetSysMenuByUId(string userId);
        /// <summary>
        /// 用户获取权限配置
        /// </summary>
        List<ClientPower> GetPowerByUId(string userId);

        #endregion
    }

    /// <summary>
    /// 权限设置管理
    /// </summary>
    public sealed class PermissionManager : IPermissionManager
    {
        private IUserService _userService;
        private IModuleService _moduleService;
        private IRoleService _roleService;
        /// <summary>
        /// 构造注入
        /// </summary>
        public PermissionManager()
        {
            this._userService = IocContainer.Resolve<IUserService>();
            this._moduleService = IocContainer.Resolve<IModuleService>();
            this._roleService = IocContainer.Resolve<IRoleService>();
        }


        /// <summary>
        /// 读取模块配置权限需要的树(带图标)
        /// </summary>
        public List<TreeBox> GetModuleTree()
        {
            if (this._moduleService == null)
                return new List<TreeBox>();

            //---按业务逻辑顺序，执行
            //01---将模块的顺表转为树结构的链表
            var MLs = this._moduleService.GetList(); //模块顺表集合
            var idSelector = FixedPointFactory.Fix<Base_Module, string>(f => (org) =>
            {
                return org.ModuleId;  //注意这里输出的节点Id，不能与默认的根节点Id相同，不然会造成死循环
            });
            var parentIdSelector = FixedPointFactory.Fix<Base_Module, string>(f => (org) =>
            {
                return string.IsNullOrWhiteSpace(org.ParentId) ? "" : org.ParentId;
            });
            var Maping = FixedPointFactory.Fix<Base_Module, TreeBox>(f => (node) =>
            {
                TreeBox newNode = new TreeBox();
                newNode.Value = node.ModuleId;
                newNode.Key = node.ResourceTypeId;
                newNode.Name = node.FullName;
                newNode.Icon = string.IsNullOrEmpty(node.ResourceTypeId) ? "fa fa-certificate" : "fa fa-bars";  //node.F_Icon;
                return newNode;
            });
            //注意根节点的默认值，若不是null的，要给参数
            var tree = MLs.GenerateTree(idSelector, parentIdSelector, Maping, x => x.Children, "").ToList();
            var loop = FixedPointFactory.Fix<List<TreeBox>>(f => (Ls) =>
            {
                if (Ls == null || Ls.Count < 1)
                    return;

                foreach (var box in Ls)
                {
                    if (!string.IsNullOrEmpty(box.Key))
                    {
                        var gk = box.Key.ToGuid();
                        if (gk.HasValue)
                        {
                            if (box.Children == null)
                                box.Children = new List<TreeBox>();
                        }
                    }

                    if (box.Children != null)
                        f(box.Children);
                }
            });
            loop(tree);
            return tree;
        }

        #region--角色配置--

        /// <summary>
        /// 获取配置在角色上的模块节点
        /// </summary>
        public Dictionary<string, bool> GetRoleModuleID(string RoleId)
        {
            if (RoleId.IsEmpty())
                return new Dictionary<string, bool>();

            //---过滤角色有效数据---输出
            var DB = STSFactory.CreateBizDB();   //数据源为NoSql
            var RMLs = DB.GetMore<No_RoleMModule>(a => a.RoleId == RoleId); //角色拥有的模块集合

            Dictionary<string, bool> MID = new Dictionary<string, bool>();
            foreach (var RM in RMLs)
                MID.Add(RM.ModuleId, RM.Undetermined);

            return MID;
        }

        /// <summary>
        /// 保存角色权限树
        /// </summary>
        public bool SaveModuleTree(string RoleId, List<SimpleItem> data)
        {
            if (RoleId.IsEmpty())
                return false;

            if (data == null || data.Count < 1)
                return false;

            if (this._roleService == null)
                return false;

            if (this._moduleService == null)
                return false;

            var RoleEn = this._roleService.GetEntity(RoleId);
            if (RoleEn == null)
                return false;

            //---还原回树结构---
            List<TreeBox> boxLs = new List<TreeBox>();
            foreach (var item in data)
            {
                string name = string.Empty;
                string PID = string.Empty;
                int op = 0;
                if (item.Key.Contains('_'))
                {
                    var id_op = CommonOP.SplitList(item.Key, '_');
                    PID = id_op[0].ToString();
                    op = id_op[1].ToIntEx();
                    name = PID;
                }
                boxLs.Add(new TreeBox
                {
                    Key = item.Key,
                    Name = name,
                    Value = item.Val,
                    ParentId = PID,
                    Grant = op,
                    HasValue = item.Seq == 0,   //undetermined的值
                    Children = new List<TreeBox>()
                });
            }
            if (boxLs.Count > 0)
            {
                var idSelector = FixedPointFactory.Fix<TreeBox, string>(f => (org) =>
                {
                    return org.Key;
                });
                var parentIdSelector = FixedPointFactory.Fix<TreeBox, string>(f => (org) =>
                {
                    return string.IsNullOrWhiteSpace(org.ParentId) ? "" : org.ParentId;
                });
                var Maping = FixedPointFactory.Fix<TreeBox, TreeBox>(f => (node) =>
                {
                    TreeBox box = new TreeBox();
                    box.Icon = node.Icon;
                    box.Key = node.Key;
                    box.Name = node.Name;
                    box.Value = node.Value;
                    box.Grant = node.Grant;
                    box.HasValue = node.HasValue;
                    box.ParentId = node.ParentId;
                    return box;
                });
                //注意根节点的默认值为""，数据节点中的Id统统不能等于""，只有ParentId可以为""
                boxLs = boxLs.GenerateTree(idSelector, parentIdSelector, Maping, x => x.Children, "").ToList();
            }

            //---填充数据---
            var MLs = this._moduleService.GetList(); //模块顺表集合--能确认资源Id
            List<No_RoleMModule> MM = new List<No_RoleMModule>();
            var loop = FixedPointFactory.Fix<List<TreeBox>, int>(f => (Ls) =>
            {
                if (Ls == null || Ls.Count < 1)
                    return 0;

                int Power = 0;
                foreach (var box in Ls)
                {
                    if (string.IsNullOrEmpty(box.Name))
                    {
                        int Grant = 0;
                        if (box.Children != null)
                            Grant = f(box.Children);

                        var mod = MLs.FirstOrDefault(a => a.ModuleId == box.Key);
                        if (mod != null)
                        {
                            No_RoleMModule NoRMod = new No_RoleMModule();
                            NoRMod.RoleId = RoleId;
                            NoRMod.ModuleId = mod.ModuleId;
                            NoRMod.ResourceId = mod.ResourceTypeId;
                            NoRMod.Undetermined = box.HasValue;
                            NoRMod.Grant = Grant;
                            MM.Add(NoRMod);
                        }
                    }
                    else
                    {
                        if (Power == 0)
                            Power = box.Grant;
                        else
                            Power = PragmaticAction.Add_Rights(Power, box.Grant);
                    }
                }
                return Power;
            });
            loop(boxLs);

            if (MM.Count > 0)
            {
                //---保存数据---
                var DB = STSFactory.CreateBizDB();   //数据源为NoSql
                //删除角色当前配置
                DB.Delete<No_RoleMModule>(a => a.RoleId == RoleId);
                System.Threading.Thread.Sleep(200);

                DB.Insert(MM);  //插入数据
                return true;
            }
            else
                return false;
        }

        #endregion

        #region--用户配置--

        /// <summary>
        /// 获取角色列表，若用户持有则seq=1
        /// </summary>
        public List<RoleModel> GetRoleListCheck(string userId)
        {
            List<string> Ls = null;
            if (userId.IsEmpty())
            {
                Ls = new List<string>();
            }
            else
            {
                var DB = STSFactory.CreateBizDB();
                var PRLs = DB.GetMore<No_RolePrincipal>(a => a.PrincipalId == userId && a.PrincipalTypeCode == "U");
                Ls = PRLs == null ? new List<string>() : PRLs.Select(a => a.RoleId).ToList();
            }

            List<RoleModel> result = this.GetRoleModel().Values.ToList();
            foreach (var item in result)
            {
                item.PrincipalId = userId;
                if (Ls.Contains(item.RoleId))
                    item.Seq = 1;
                else
                    item.Seq = 0;
            }

            return result;
        }
        /// <summary>
        /// 所有角色数据的映射字典
        /// </summary>
        private Dictionary<string, RoleModel> GetRoleModel()
        {
            Dictionary<string, RoleModel> dic = new Dictionary<string, RoleModel>();
            if (this._roleService == null)
                return dic;

            var list = this._roleService.GetList();
            foreach (var item in list)
            {
                RoleModel model = new RoleModel()
                {
                    RoleId = item.RoleId,
                    RoleCode = item.RoleCode,
                    RoleName = item.FullName
                };
                dic.Add(item.RoleId, model);
            }
            return dic;
        }

        public List<RoleModel> GetRoleList(string userId)
        {
            List<RoleModel> result = this.GetRoleListCheck(userId);
            result = result.Where(a => a.Seq != 0).ToList();
            return result;
        }

        /// <summary>
        /// 保存用户角色配置
        /// </summary>
        public bool SaveURConfig(string userId, List<RoleModel> Rolels)
        {
            if (userId.IsEmpty())
                return false;

            if (Rolels == null)
                Rolels = new List<RoleModel>();

            var DB = STSFactory.CreateBizDB();
            DB.Delete<No_RolePrincipal>(a => a.PrincipalId == userId && a.PrincipalTypeCode == "U");
            System.Threading.Thread.Sleep(200);

            if (!Rolels.Any())
                return true;

            List<No_RolePrincipal> data = new List<No_RolePrincipal>();
            foreach (var item in Rolels)
            {
                No_RolePrincipal RP = new No_RolePrincipal();
                RP.RoleId = item.RoleId;
                RP.PrincipalId = userId;
                RP.PrincipalTypeCode = "U";
                RP.Enabled = true;
                data.Add(RP);
            }
            if (data.Count > 0)
                DB.Insert(data);  //插入数据

            return true;
        }

        #endregion

        #region----获取权限配置----

        /// <summary>
        /// 取角色配置的模块列表
        /// </summary>
        public List<ModuleModel> GetModuleFromRole(string roleId)
        {
            List<ModuleModel> MLs = new List<ModuleModel>();
            if (roleId.IsEmpty())
                return MLs;

            if (this._roleService == null)
                return MLs;

            var roleEn = this._roleService.GetEntity(roleId).OrElse(() => FP.Async(default(Base_Role))).Result;
            if (roleEn == null)
                return MLs;

            var DB = STSFactory.CreateBizDB();
            var MMLs = DB.GetMore<No_RoleMModule>(a => a.RoleId == roleId);
            var MoEnLs = this.GetListByRoleId(MMLs.Select(a => a.ModuleId).ToList());

            if (MoEnLs != null)
            {
                foreach (var en in MoEnLs)
                {
                    var mm = new ModuleModel
                    {
                        ModuleId = en.ModuleId,
                        ParentId = en.ParentId,
                        ModuleCode = en.ModuleCode,
                        ModuleName = en.FullName,
                        ModuleIcon = en.Icon,
                        ResourceTypeId = en.ResourceTypeId,
                        ResourceTypeName = en.ResourceTypeName,
                        HasDataPower = false
                    };
                    MLs.Add(mm);
                }
            }
            return MLs;
        }
        /// <summary>
        /// 通过角色配置的ID取模块数据
        /// </summary>
        private List<Base_Module> GetListByRoleId(List<string> MIdLs)
        {
            if (MIdLs == null || MIdLs.Count < 1)
                return new List<Base_Module>();

            if (this._moduleService == null)
                return new List<Base_Module>();

            var Ls = this._moduleService.GetList().Where(a => a.IsPublic && a.IsMenu).ToList();
            return Ls.FindAll(t => MIdLs.Contains(t.ModuleId));
        }

        /// <summary>
        /// 通过用户取菜单数据
        /// </summary>
        public List<SysMenu> GetSysMenuByUId(string userId)
        {
            if (userId.IsEmpty())
                return new List<SysMenu>();

            var userEn = this.GetEn(userId);
            if (userEn == null)
                return new List<SysMenu>();

            List<SysMenu> MLs = null;
            if (userEn.IsAdmin)
                MLs = this.GetModuleByAdmin();
            else
                MLs = this.GetModuleByPrincipal(userEn.UserId);

            return MLs;
        }
        private Base_User GetEn(string userId)
        {
            if (this._userService == null)
                return null;
            else
                return this._userService.GetEntity(userId).OrElse(() => FP.Async(default(Base_User))).Result;
        }
        /// <summary>
        /// 通过主体取菜单数据
        /// </summary>
        private List<SysMenu> GetModuleByPrincipal(string principalId)
        {
            List<SysMenu> MLs = new List<SysMenu>();
            if (principalId.IsEmpty())
                return MLs;

            var DB = STSFactory.CreateBizDB();
            var PRLs = DB.GetMore<No_RolePrincipal>(a => a.PrincipalId == principalId && a.PrincipalTypeCode == "U");
            List<string> RLs = PRLs == null ? new List<string>() : PRLs.Select(a => a.RoleId).ToList();

            if (!RLs.IsNotNullOrEmpty())
                return MLs;

            var MMLs = DB.GetMore<No_RoleMModule>(a => RLs.Contains(a.RoleId));
            var MoEnLs = this.GetListByRoleId(MMLs.Select(a => a.ModuleId).ToList());

            if (MoEnLs != null)
                foreach (var en in MoEnLs)
                {
                    MLs.Add(new SysMenu
                    {
                        Module_Id = en.ModuleId,
                        Parent_Id = en.ParentId,
                        Module_Code = en.ModuleCode,
                        Module_Name = en.FullName,
                        Module_Icon = en.Icon,
                        Module_Action = en.ActionAddress,
                        Module_Address = en.IndexAddress,
                        AddTime = en.Modified()
                    });
                }

            return MLs;
        }
        private List<SysMenu> GetModuleByAdmin()
        {
            List<SysMenu> MLs = new List<SysMenu>();
            if (this._moduleService == null)
                return MLs;

            var MoEnLs = this._moduleService.GetList();

            if (MoEnLs != null)
                foreach (var en in MoEnLs)
                {
                    MLs.Add(new SysMenu
                    {
                        Module_Id = en.ModuleId,
                        Parent_Id = en.ParentId,
                        Module_Code = en.ModuleCode,
                        Module_Name = en.FullName,
                        Module_Icon = en.Icon,
                        Module_Action = en.ActionAddress,
                        Module_Address = en.IndexAddress,
                        AddTime = en.Modified()
                    });
                }

            return MLs;
        }

        /// <summary>
        /// 通过用户取权限数据
        /// </summary>
        public List<ClientPower> GetPowerByUId(string userId)
        {
            List<ClientPower> CPLs = new List<ClientPower>();
            if (userId.IsEmpty())
                return CPLs;

            var DB = STSFactory.CreateBizDB();
            var PRLs = DB.GetMore<No_RolePrincipal>(a => a.PrincipalId == userId && a.PrincipalTypeCode == "U");
            List<string> RLs = PRLs == null ? new List<string>() : PRLs.Select(a => a.RoleId).ToList();

            if (!RLs.IsNotNullOrEmpty())
                return CPLs;

            var MMLs = DB.GetMore<No_RoleMModule>(a => RLs.Contains(a.RoleId));
            if (MMLs != null)
                foreach (var en in MMLs)
                {
                    CPLs.Add(new ClientPower
                    {
                        RoleId = en.RoleId,
                        ModuleId = en.ModuleId,
                        ResourceId = en.ResourceId,
                        Grant = en.Grant
                    });
                }

            return CPLs;
        }

        #endregion
    }
}
